//	KademliaMain.cpp : Kademlia implementation for Grade32 active network server.
//
//	Author: Miroslav Hauser, hauz {at} students.zcu.cz
//	Version: 0.9
//
#include "GradeIface.h"
#include "kademliamain.h"
#include "dataprovider.h"
#include "../gui/resource.h"
#include "ui/GuiDialog.h"
#include "gkadpingiface.h"

#include "kademlia/kadmetrics.h"
#include "kademlia/kuid.h"

#include "utils/gradeutils.h"
#include "utils/configreader.h"

#include <direct.h>
#include "sys/stat.h"
#include <Windows.h>
#include <iostream>
#include <fstream>

#include <string>
#include <map>

using namespace gKad;

using std::string;
using std::map;

//	!!! Kademlia config file !!!
//
//	Once changed, rename the config file immediately.
//
const char *configFile = "gKad.cfg";

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

//KademliaMain::KademliaMain(IAppAPI *api, HMODULE modHandler) {
	//i_api->RegisterListener(this);
	//waitEvent = CreateEvent(NULL, false, false, NULL);
	//InitializeCriticalSection(&fileLock);
//}

KademliaMain::KademliaMain() { }

void KademliaMain::Init() {
	dataProvider = new DataProvider(iApi);
	dataProvider->ConfigRead(configFile);
}

void KademliaMain::SetIAppAPI(IAppAPI *api) {
	iApi = api;

	iApi->GetLogger(&logger);

	iApi->GetID(&serverId);

	IServer	*server;
	iApi->GetServer(&server);
	server->Address(&serverAddr);
}

void KademliaMain::SetHModule(HMODULE hMod) {
	moduleHandle = hMod;
}

KademliaMain *KademliaMain::GetInstance() {
	// TODO add locking

	static KademliaMain *instance = new KademliaMain;

	return instance;
}

TGradeAddr KademliaMain::GetServerAddr() {
	return serverAddr;
}

HMODULE KademliaMain::GetServerHmodule() {
	return moduleHandle;
}

IAppAPI	*KademliaMain::GetServerIApi() {
	return iApi;
}

TAppID *KademliaMain::GetServerId() {
	return &serverId;
}

void KademliaMain::WriteLog(string line) {
	logger->LogString(const_cast<char *> (line.c_str()));
}

// Main entry point
void KademliaMain::Execute() {
	// init all components
	Init ();

	// try to boot into kademlia network
	switch (dataProvider->Bootstrap()) {
		case b_BOOTUP_OK:			// ready to roll
			// TODO 
			WriteLog("WooooooooHooooo ... ALIVE !!!");
			break;
		case b_BOOTUP_START_SERVER:	// becomming boot node
			// TODO
			WriteLog("BECOMMING BOOTUP SERVER");
			break;
		case b_BOOTUP_FAIL:			// Doh!
			WriteLog("[ERROR] Boot-up node is down! Please doublecheck config.");
			MessageBoxW(NULL, 
				L"Could not connect to boot-up node.", L"Critical Error", MB_OK);
			break;
	}

	//WriteIntoLog(dataProvider->ConfigGetKey("bootstrap_address"));

	
	//string temp("bootstrap_address");
	//WriteIntoLog(dataProvider->ConfigGetKey(temp));


	//struct file_request	getFileRequest;
	//IServer				*i_server;
	//IStream				*stream;

	//// prepare capsule to send
	//if (i_api->GetServer(&i_server) == S_OK) {

	//	// trigger dialog and get data
	//	getDestAndFileName(&getFileRequest);

	//	i_server->Address(&getFileRequest.srcAddr);
	//	TAppID temp = i_api->GetID();
	//	getFileRequest.srcApp = temp;
	//	// FIXME
	//	// Causes exception - memory acces viloation - ???
	//	//getFileRequest.srcApp = i_api->GetID();

	//	// add filename
	//	i_api->CreateStream(&stream);
	//	stream->Write(&getFileRequest, sizeof(getFileRequest), NULL);
	//	i_api->InjectCapsule(NULL, stream, getFileRequest.destAddr, InjectMaxTTL);	
	//	//i_api->InjectCapsule(NULL, stream, getFileRequest.destAddr, 4);	
	//}

	//IServer			*server;
	//IStream			*stream;
	//struct s_ping	pingData;
	//struct file_request	fr;

	//i_api->GetServer(&server);
	//getDestAndFileName(&fr);

	//pingData.dstAddr = fr.destAddr;
	//TAppID temp = i_api->GetID();
	//return;
	//pingData.srcApp = temp;
	//pingData.alive = false;
	//server->Address(&pingData.srcAddr);

	//i_api->CreateStream(&stream);
	//stream->Write(&pingData, sizeof(pingData), NULL);
	//i_api->InjectCapsule("gkadping.dll", stream, pingData.dstAddr, InjectMaxTTL);

	//WaitForSingleObject(waitEvent, INFINITE);
}

void KademliaMain::getDestAndFileName(struct file_request *desiredFile) {
	// show dialog
	//struct dest_dlg_result *dlg_result;
	//dlg_result = (struct dest_dlg_result *) DialogBoxParam(moduleHandle, 
	//	MAKEINTRESOURCE(IDD_DIALOG1), 0, DlgProc, 0);

	//char buf[MAX_FILE_NAME_LEN];
	//size_t converted_chars;
	//wcstombs_s(&converted_chars, buf, wcslen(dlg_result->file_name) + 1,
	//	dlg_result->file_name, _TRUNCATE);	// +1 for '\0' character

	//desiredFile->destAddr = dlg_result->addr;
	//strncpy_s(desiredFile->fileName, buf, MAX_FILE_NAME_LEN);
}